package com.vecspace.utils;

import java.io.StringWriter;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.vecspace.utils.datetime.LocalDateTimeISOSerializer;
import com.vecspace.utils.datetime.MyLocalDateTimeDeserializer;

public class TJSON {
	private final static TypeFactory TYPEFACTORY = TypeFactory.defaultInstance();

	static ObjectMapper mapper;
	private static ObjectMapper buildJSONMapper(){
		if(mapper == null){
			synchronized (TJSON.class){
				if(mapper == null){
					ObjectMapper mapper1 = new ObjectMapper();
					mapper1.setDateFormat(new IsoDateFormat());
					mapper1.setTimeZone(TimeZone.getDefault());
					mapper1.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

					JavaTimeModule timeModule = new JavaTimeModule();

					timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
					timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));

					timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeISOSerializer());
					timeModule.addDeserializer(LocalDateTime.class, new MyLocalDateTimeDeserializer());

					timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
					timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));

					mapper1.registerModule(timeModule);

					mapper = mapper1;
				}
			}
		}

		return mapper;
	}
	
	public static String toJSONString(Object obj) throws JsonProcessingException {
		String json = "";
		if(obj == null)return "";
		try {
			ObjectMapper mapper = buildJSONMapper();
			json = mapper.writeValueAsString(obj);
		} catch (JsonProcessingException e) {
			throw e;
		}
		 
		return json;
	}

	public static String printJsonString(Object obj) {
		String json = null;
		try {
			json = toJSONString(obj);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		System.out.println(json);
		return json;
	}

	/**把json字符串转为Java对象
	 * 
	 * @param <T>
	 * @param returnType 对象类型
	 * @param jsonText
	 * @return 
	 * @author: wanghua
	 */
	@SuppressWarnings("unchecked")
	public static <T> T convertToObject(Class<?> returnType, String jsonText) throws JsonProcessingException {
		try {
			ObjectMapper mapper = buildJSONMapper();
			T t = (T) mapper.readValue(jsonText, returnType);
			return t;
		} catch (Exception e) {
			throw e;
		}
	}

	/**返回 T&ltK&gt 类型的对象
	 * 
	 * @param t T类
	 * @param k K类
	 * @param jsonText
	 * @return 
	 * @author: wanghua
	 */
    public static Object convertToObject(Class<?> t, Class<?> k, String jsonText) throws Exception{
		ObjectMapper mapper = buildJSONMapper();
        com.fasterxml.jackson.databind.JavaType javaType = mapper.getTypeFactory().constructParametricType(t, k);
        Object obj = mapper.readValue(jsonText, javaType);
        return obj;
    }
    
	/**把json字符串转为List对象，
	 *  
	 * @param clazz List的泛型类型
	 * @param jsonVal
	 * @return 
	 * @author: wanghua
	 */
	public static <T> List<T> convertToList(Class<?> clazz, String jsonVal) {
		if(jsonVal == null || jsonVal.length()==0) {
			return null;
		}
		TypeFactory t = TypeFactory.defaultInstance();
		// 指定容器结构和类型（这里是ArrayList和clazz）
		List<T> list = null;
		 
		try {
			ObjectMapper mapper = buildJSONMapper();
			list = mapper.readValue(jsonVal, t.constructCollectionType(
					ArrayList.class, clazz));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	public static String Encode(Object obj) {
		String json = null;
		try {
			StringWriter sw = new StringWriter();
			try (sw; JsonGenerator gen = new JsonFactory().createGenerator(sw)) {
				ObjectMapper mapper = buildJSONMapper();
				mapper.writeValue(gen, obj);
				json = sw.toString();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return json;
	}	

	/**把json字符串转为数组
	 * 
	 * @param clazz 数组元素的类型
	 * @param jsonVal
	 * @return 
	 * @author: wanghua
	 */
	public static Object[] convertToArray(Class<?> clazz, String jsonVal) {
		List<?> list = convertToList(clazz,jsonVal);
		return list.toArray();
	}
	
	/***
	 * 将字符串中的特殊字符进行转换处理
	 * 注意：拼接JSON字符串时，必须使用单引号<'>将字符串括起来，不能使用双引号<">
	 * 功能描述：
	 * @param str
	 * @return 
	 * @author: wanghua
	 */
	public static String StringToJSON(String str) {
        str = str == null ? "" : str;
        StringBuilder buffer = new StringBuilder(str);
        int i = 0;
        while (i < buffer.length()) {
         if (buffer.charAt(i) == '\'' || buffer.charAt(i) == '\\') {
          buffer.insert(i, '\\');
          i += 2;
         } else {
          i++;
         }
       }
        return buffer.toString();
	}
	/**
	 * 
	 * 功能描述：json字符串转换为List<Map>
	 * @param jsonVal
	 * @return 
	 * @author: wanghua
	 */
	public static List<Map<String, Object>> toMapList(String jsonVal) {
		List<Map<String, Object>> list = new ArrayList<>();
		try {
			ObjectMapper mapper = buildJSONMapper();
			list = mapper.readValue(jsonVal, TYPEFACTORY
					.constructCollectionType(ArrayList.class, TYPEFACTORY
							.constructMapLikeType(HashMap.class, String.class,Object.class)));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}
	/**
	 * 
	 * 功能描述：json字符串转换为List<Map>
	 * @param jsonVal
	 * @return 
	 * @author: wanghua
	 */
	public static Map<String, Object> toMap(String jsonVal) {
		Map<String, Object> map = new HashMap<>();
		try {
			ObjectMapper mapper = buildJSONMapper();
			map = mapper.readValue(jsonVal, TYPEFACTORY
					.constructMapLikeType(HashMap.class, String.class,Object.class));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}
}
/*
 * 时间的格式化和解析，统一采用 ISO 8601 格式
 */
class IsoDateFormat extends SimpleDateFormat {
	private static final long serialVersionUID = 231455557511778127L;

	public IsoDateFormat(){
		super();
	}
	
	public IsoDateFormat(String formater){
		super(formater);
	}
	
	@Override
	public Date parse(String source) throws ParseException {
		return DateTimeUtil.parseIsoDate(source);
	}

	@Override
	public StringBuffer format(Date date, StringBuffer toAppendTo,	FieldPosition pos) {
		return new StringBuffer(DateTimeUtil.formatToIsoDate(date));
	}
}
